using System;
using System.Collections.Generic;
using System.Reflection;
using Autofac.Features.Indexed;
using UnityEngine;
using Debug = UnityEngine.Debug;
using Object = UnityEngine.Object;

namespace ExceptionModule
{
    /// <summary>
    /// 日志处理器
    /// </summary>
    public class LogHandler : ICustomLogHandler, ILogHandler
    {
        private readonly ILogConfiguration _logConfiguration;
        private readonly IIndex<int, ICustomLogHandler> _customLogHandler;
        private readonly List<ICustomLogHandler> _handlers = new List<ICustomLogHandler>(3);
        private readonly ILogHandler _defaultLogHandler;

        public LogHandler(ILogConfiguration logConfiguration, IIndex<int, ICustomLogHandler> customLogHandler)
        {
            _defaultLogHandler = Debug.unityLogger.logHandler;
            _logConfiguration = logConfiguration;
            _customLogHandler = customLogHandler;
            Debug.unityLogger.logHandler = this;
        }

        public void LogFormat(LogType logType, Object context, string format, params object[] args)
        {
            _defaultLogHandler.LogFormat(logType, context, format, args);
        }

        public void LogException(Exception exception, Object context)
        {
            exception = GetInnerException(exception);
            var method = StacktraceHelper.GetExceptionTargetSite(exception);
            var logHandlerType = _logConfiguration.GetLogHandlerType(method, LogType.Exception);
            HandleLog(exception.Message, exception.StackTrace, LogType.Exception, logHandlerType, method);
            _defaultLogHandler.LogException(exception, context);
        }

        private Exception GetInnerException(Exception e)
        {
            if (e.InnerException == null)
                return e;
            return GetInnerException(e.InnerException);
        }

        public void HandleLog(string logString, string stackTrace, LogType type)
        {
            if (type == LogType.Exception)
                return;

            var method = StacktraceHelper.GetLogTargetSite();
            var logHandlerType = _logConfiguration.GetLogHandlerType(method, type);

            HandleLog(logString, stackTrace, type, logHandlerType, method);
        }

        private void HandleLog(string logString, string stackTrace, LogType type, int logHandlerType, MethodBase method)
        {
            var author = _logConfiguration.GetModuleAuthor(method);
            logString = $"模块异常，请联系负责人:{author}, 异常原因：{logString}";
            AddHandlers(logHandlerType);
            foreach (var handler in _handlers)
            {
                handler.HandleLog(logString, stackTrace, type);
            }

            _handlers.Clear();
        }

        public void Dispose()
        {
            Debug.unityLogger.logHandler = _defaultLogHandler;
        }

        private void AddHandlers(int logHandlerType)
        {
            AddHandler(logHandlerType, LogHandleType.LogToConsole);
            AddHandler(logHandlerType, LogHandleType.LogToFile);
            AddHandler(logHandlerType, LogHandleType.LogToUI);
        }

        private void AddHandler(int logHandlerType, int expectHandlerType)
        {
            if ((logHandlerType & expectHandlerType) == expectHandlerType)
            {
                var handler = _customLogHandler[expectHandlerType];
                _handlers.Add(handler);
            }
        }
    }
}